package com.zhny.aiot.three.ball.valve.plugin;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.zhny.aiot.plugin.ICenterFacilities;
import com.zhny.aiot.plugin.IDeviceFactory;
import com.zhny.aiot.plugin.core.utils.MessageUtils;
import com.zhny.aiot.plugin.model.DeviceEntity;
import com.zhny.aiot.plugin.model.MessageEntry;
import com.zhny.aiot.plugin.model.MessageType;
import com.zhny.aiot.plugin.model.TaskEntity;
import com.zhny.aiot.plugin.zhnygateway.GatewayEngine;
import com.zhny.aiot.plugin.zhnygateway.device.ZhnyConfig;
import com.zhny.aiot.plugin.zhnygateway.device.ZhnyDevice;
import com.zhny.aiot.plugin.zhnygateway.model.GatewayResponseMessage;
import com.zhny.aiot.plugin.zhnygateway.model.NodeRequestMessage;
import com.zhny.aiot.three.ball.valve.plugin.model.BallThreeValveStoreEntry;
import com.zhny.aiot.three.ball.valve.plugin.model.ComParam;
import com.zhny.aiot.three.ball.valve.plugin.model.InputParam;
import io.netty.buffer.ByteBuf;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

public class BallThreeValveDevice extends ZhnyDevice<BallThreeValveStoreEntry> {
    private static final Logger logger = LoggerFactory.getLogger(BallThreeValveDevice.class);
    private final Map<String, ComParam> CommandOperations;
    public BallThreeValveDevice(GatewayEngine engine, IDeviceFactory<ZhnyConfig> factory, ICenterFacilities centerFacilities, DeviceEntity entity) {
        super(engine, factory, centerFacilities, entity);
        CommandOperations =  new ImmutableMap.Builder<String, ComParam>()
                .put("aValue", new ComParam(0x32,getzhnyType()))
                .put("bValue", new ComParam(0x33,getzhnyType()))
                .put("upDownQuery", new ComParam(0x30,getzhnyType()))
                .put("query", new ComParam(0x39,getzhnyType()))
                .put("queryPressure", new ComParam( 0x3B,getzhnyType()))
                .put("upValue", new ComParam(0x37,getzhnyType()))
                .put("downValue", new ComParam(0x38,getzhnyType()))
                .put("queryVoltage", new ComParam(0x3A,getzhnyType())).build();
    }

    @Override
    public void onDecoder(GatewayResponseMessage message) {
        logger.info (message.toString ());
        int type = message.getDeviceType ();
        if(type == 0x20){
            logger.info("---start decoder three ball valve message---");
            onMessage(message);
        }
        if(message.getDeviceData() !=null)
            message.getDeviceData ().release ();
    }

    private void onMessage(GatewayResponseMessage message) {
        MessageEntry resultMsg = MessageUtils.createMessageEntry (this.getId ());
        resultMsg.setType(MessageType.RESULT);
        BallThreeValveStoreEntry storeEntry = new BallThreeValveStoreEntry ();
        logger.info ("------three boll valve decode start------");
        int operation = message.getDeviceOper ();
        if(operation >= 0x31 && operation <= 0x34){
            if(message.getDataLength () == 7){
                resultMsg.setType (MessageType.ERROR);
                resultMsg.setData ("水利机械阀加入任务失败");
                logger.error ("[deviceNo:{},controllerNo:{}] 水利机械阀加入任务[{}]失败"
                        , getConfig ().getAddress (), getConfig ().getChannelNo (), operation);
                nofity (resultMsg);
                return;
            } else if(operation == 0x31){
                storeEntry.setAStatus ("0");
                storeEntry.setBStatus ("0");
                storeEntry.setVoltage (createVol(message.getDeviceData ().readShort ()));
                resultMsg.setData (storeEntry);
            } else if(operation == 0x32){
                int value = message.getDeviceData ().readByte ();
                int vol = message.getDeviceData ().readUnsignedShort ();
                storeEntry.setAStatus (String.valueOf (value));
                storeEntry.setBStatus ("0");
                storeEntry.setVoltage (createVol (vol));
                resultMsg.setData (storeEntry);
            } else if(operation == 0x33){
                int value = message.getDeviceData ().readByte ();
                int vol = message.getDeviceData ().readUnsignedShort ();
                storeEntry.setAStatus ("0");
                storeEntry.setBStatus (String.valueOf (value));
                storeEntry.setVoltage (createVol (vol));
                resultMsg.setData (storeEntry);
            }
        } else if(operation == 0x35) {
            int range = message.getDeviceData ().readByte ()& 0xff;
            int value = message.getDeviceData ().readByte ()& 0xff;
            if(range == 0){ /*00表示A通道压力小于压力下限值*/
                storeEntry.setAPressure (String.format ("压力低！当前%s",value));
                storeEntry.setBPressure ("0");
            }else if(range == 1) {  /*01表示A通道压力大于压力上限值*/
                storeEntry.setAPressure (String.format ("压力大！当前%s",value));
                storeEntry.setBPressure ("0");
            }else if(range == 16) { /*10表示B通道压力小于压力下限值*/
                storeEntry.setBPressure (String.format ("压力低！当前%s",value));
                storeEntry.setAPressure ("0");
            }else if(range == 17) { /*11表示B通道压力大于压力上限值*/
                storeEntry.setBPressure (String.format ("压力大！当前%s",value));
                storeEntry.setAPressure ("0");
            }
            resultMsg.setData (storeEntry);
        }else if(operation == 0x37){
            int maxp = message.getDeviceData ().readByte ()& 0xff;
            storeEntry.setPressureUp (String.valueOf (maxp));
            resultMsg.setData (storeEntry);
        }else if(operation == 0x38){
            int maxp = message.getDeviceData ().readByte ()& 0xff;
            storeEntry.setPressureUp (String.valueOf (maxp));
            resultMsg.setData (storeEntry);
        }else if(operation == 0x39){
            int aValue = message.getDeviceData ().readByte ();
            int bValue = message.getDeviceData ().readByte ();
            String vol = createVol(message.getDeviceData ().readUnsignedShort ());
            storeEntry.setAStatus (String.valueOf (aValue));
            storeEntry.setBStatus (String.valueOf (bValue));
            storeEntry.setVoltage (vol);
            resultMsg.setData (storeEntry);
        }else if(operation == 0x3A){
            storeEntry.setVoltage (createVol(message.getDeviceData ().readUnsignedShort ()));
            resultMsg.setData (storeEntry);
        }else if(operation == 0x3B){
            storeEntry.setAPressure (createPressure (message.getDeviceData ().readByte () & 0xff));
            storeEntry.setBPressure (createPressure (message.getDeviceData ().readByte () & 0xff));
            storeEntry.setVoltage (createVol (message.getDeviceData ().readUnsignedShort ()));
            resultMsg.setData (storeEntry);
        }
        logger.info("three ball valve store[{}]",storeEntry.toString());
        save (storeEntry);
        saveReal (storeEntry);
        nofity (resultMsg);
    }

    private String createPressure(int pressure) {
        double result =pressure / 100.00;
        return  String.format("%.2f",result);
    }

    private String createVol(int vol){
//        V=(VH*256+VL)/1000
        Double value =vol / 1000.00;
        String result = value <= 6?String.format ("电压过低!当前值%.2f",value):String.format ("%.2f",value);
        return result;
    }


    @Override
    protected NodeRequestMessage onCommand(TaskEntity taskEntity) {
        InputParam param = null;
        if(StringUtils.isNullOrEmpty (taskEntity.getMethodName ()))
            return null;
        if(!StringUtils.isNullOrEmpty(taskEntity.getParams ())){
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            try{
                param = mapper.readValue (taskEntity.getParams (),InputParam.class);
            }catch (Exception e){
                logger.error ("Parse param error !");
                return  null;
            }
        }
        Map<String,Object> command = new HashMap<String, Object>();
        command.put (taskEntity.getMethodName (),param);
        logger.info ("three ball valve command[{}] gprs[{}] address[{}]",taskEntity.getMethodName (),
                getConfig ().getGprsNo (),Integer.parseInt (getConfig ().getAddress ()));
        return encode (command);
    }

    private NodeRequestMessage encode(Map<String, Object> commandMap) {
        for (String id : commandMap.keySet ()){
            if(CommandOperations.containsKey(id)) {
                byte[] data = null;
                ComParam param=CommandOperations.get(id);
                Integer oper = param.getCommand();
                Integer deviceType = param.getDeviceType();
                Object obj = commandMap.get (id);
                if(obj != null){
                    InputParam par = (InputParam)obj;
                    data = new byte[]{par.getValue ()};
                }
                int length = data != null?data.length + 4 : 4;
                return new NodeRequestMessage (deviceType + 128,length,oper,Integer.parseInt (getConfig ().getAddress ()),data);
            }
        }
        return null;
    }

    @Override
    protected int getzhnyType() {
        return 32;
    }

    @Override
    protected void disposable() {

    }
}
